package com.example.literj.kt.internal.util

import com.example.literj.kt.exceptions.CompositeException
import java.util.concurrent.atomic.AtomicReference

object ExceptionHelper {
    val TERMINATED: Throwable = Termination()

    internal class Termination : Throwable("No further exceptions") {
        override fun fillInStackTrace(): Throwable {
            return this
        }
    }

    fun createNullPointerException(prefix: String?): NullPointerException {
        return NullPointerException(nullWarning(prefix))
    }

    fun addThrowable(field: AtomicReference<Throwable>, exception: Throwable): Boolean {
        while (true) {
            val cur = field.get()
            if (cur == TERMINATED) return false

            val update = if (cur == null) {
                exception
            } else {
                CompositeException(cur, exception)
            }

            if (field.compareAndSet(cur, update)) return true
        }
    }

    fun terminate(field: AtomicReference<Throwable>): Throwable? {
        var current = field.get()
        if (current != TERMINATED) {
            current = field.getAndSet(TERMINATED)
        }
        return current
    }

    fun nullWarning(prefix: String?): String {
        return "$prefix Null values are generally not allowed in 3.x operators and sources."
    }

    fun wrapOrThrow(error: Throwable?): RuntimeException {
        if (error is Error) {
            throw (error as? Error)!!
        }
        return if (error is RuntimeException) {
            error
        } else RuntimeException(error)
    }
}